﻿Imports System.IO
Imports System.Drawing
Partial Public Class document
#Region "重置各种标志位"
    Sub ResetFlags()
        ResetCanBeFolder()
        ResetComment()
    End Sub
    ''' <summary>
    ''' 载入文档后，对整个文档的块状注释进行调整
    ''' </summary>
    ''' <remarks></remarks>
    Sub ResetComment()
        '如果不存在块注释符号，跳过这个步骤
        If BlockCommentStartMark = String.Empty Or BlockCommentEndMark = String.Empty Then Exit Sub
        '当前检测行是否处于块注释状态
        Dim IsInBlockComment As Boolean = False
        For tempCount As Integer = 1 To ExRealLineManager.Count
            ExRealLineManager.ResetBlockComment(tempCount)
            ExRealLineManager.GetInfoLine(tempCount).Real_IsCommentLine = False
            If IsInBlockComment Then
                '如果在块状态
                ExRealLineManager.GetInfoLine(tempCount).Real_IsCommentLine = True
                If ExRealLineManager.GetInfoLine(tempCount).Real_IsCommentEnd Then IsInBlockComment = False
            Else
                ExRealLineManager.GetInfoLine(tempCount).Real_IsCommentLine = False
                If ExRealLineManager.GetInfoLine(tempCount).Real_IsCommentStart Then
                    ExRealLineManager.GetInfoLine(tempCount).Real_IsCommentLine = True
                    IsInBlockComment = True
                End If
            End If
        Next
    End Sub
    ''' <summary>
    ''' 重新设置能不能被折叠的行属性
    ''' </summary>
    ''' <remarks></remarks>
    Sub ResetCanBeFolder()
        Dim RealLineCount As Integer = 1
        Dim BlockEndRealLineNo As Integer
        Do While RealLineCount <= MaxRealLineNumber
            With ExRealLineManager.GetInfoLine(RealLineCount)
                If .Real_IsBlockHeader Then
                    BlockEndRealLineNo = GetBlockFooterRealNo(RealLineCount)
                    If BlockEndRealLineNo = 0 Then
                        For i As Integer = .Real_MemoryStartLineNo To .Real_MemoryEndLineNo
                            GetMemoryLine(i).Dis_CodeFold = Line.CodeFoldType.None
                        Next
                        RealLineCount += 1
                    Else
                        For i As Integer = RealLineCount To BlockEndRealLineNo
                            .Real_CanBeFolder = True
                        Next
                        For i As Integer = .Real_MemoryStartLineNo To ExRealLineManager.GetInfoLine(BlockEndRealLineNo).Real_MemoryEndLineNo
                            GetMemoryLine(i).Dis_CodeFold = Line.CodeFoldType.Whole
                        Next
                        GetMemoryLine(.Real_MemoryStartLineNo).Dis_CodeFold = Line.CodeFoldType.Footer
                        GetMemoryLine(ExRealLineManager.GetInfoLine(BlockEndRealLineNo).Real_MemoryEndLineNo).Dis_CodeFold = Line.CodeFoldType.Header
                        RealLineCount = BlockEndRealLineNo + 1
                    End If
                Else
                    For i As Integer = .Real_MemoryStartLineNo To .Real_MemoryEndLineNo
                        GetMemoryLine(i).Dis_CodeFold = Line.CodeFoldType.None
                    Next
                    RealLineCount += 1
                End If
            End With
        Loop
    End Sub
#End Region
#Region "测试用方法"
    ''' <summary>
    ''' 打印行信息[测试用]
    ''' </summary>
    ''' <remarks></remarks>
    Sub DumpLines()
        Dim DebugFile As New StreamWriter(System.Windows.Forms.Application.StartupPath & "\DumpFile.txt", False, Encoding.Unicode)
        For LineCount As Integer = 0 To MaxMemoryLineNumber - 1
            DebugFile.WriteLine(Format(LineCount, "000#") & " " & IIf(MemoryLines(LineCount).HasSelection, "True ", "False") & " " & Format(LineCount, "0000#") & ":" & MemoryLines(LineCount).Text)
        Next
        DebugFile.Close()
        System.Diagnostics.Process.Start(System.Windows.Forms.Application.StartupPath & "\DumpFile.txt")
    End Sub
    ''' <summary>
    ''' 表示出当前选中文字[测试用]
    ''' </summary>
    ''' <remarks></remarks>
    Sub ShowSelection()
        MsgBox("[" & GetSelectionText() & "]", , "选中文本")
    End Sub
    ''' <summary>
    ''' 智能补完前缀[测试用]
    ''' </summary>
    ''' <remarks></remarks>
    Sub ShowAutoFill()
        MsgBox("[" & GetLastWord() & "]", , "智能补完")
    End Sub
    ''' <summary>
    ''' 显示全部行
    ''' </summary>
    ''' <remarks></remarks>
    Sub ShowAllLines()
        For i As Integer = 1 To ExDocument.MaxRealLineNumber
            ExRealLineManager.GetInfoLine(i).Real_IsHidden = False
        Next
    End Sub
    ''' <summary>
    ''' 模拟代码折叠
    ''' </summary>
    ''' <remarks></remarks>
    Sub HideHalfLines()
        For i As Integer = 1 To ExDocument.MaxRealLineNumber
            With ExRealLineManager.GetInfoLine(i)
                If (i Mod 100) = 1 Then
                    .Real_IsBlockHeader = True
                    .Real_CanBeFolder = True
                    .Real_IsFolder = False
                End If
                If (i Mod 100) > 1 And (i Mod 100) < 21 Then
                    .Real_IsHidden = False
                    .Real_CanBeFolder = True
                End If
                If (i Mod 100) = 20 Then
                    .Real_IsBlockFooter = True
                End If
            End With
        Next
    End Sub
    Sub DumpExList()
        Dim T As String
        T = "ExDisplayManager" & vbCrLf
        For i As Byte = 1 To ExDisplayManager.Count
            T &= ExDisplayManager.GetDisplayNoByMemoryNo(i) & vbCrLf
        Next
        MsgBox(T)
    End Sub
#End Region
#Region "选择系"
    ''' <summary>
    ''' 选中文本起始位置
    ''' </summary>
    ''' <remarks></remarks>
    Public SelectStartRealPos As Point = New Point(0, 0)
    ''' <summary>
    ''' 选中文本结束位置
    ''' </summary>
    ''' <remarks></remarks>
    Public SelectEndRealPos As Point = New Point(0, 0)
    Enum SelectType
        ''' <summary>
        ''' 普通
        ''' </summary>
        ''' <remarks></remarks>
        Normal
        ''' <summary>
        ''' 箱型
        ''' </summary>
        ''' <remarks></remarks>
        Box
    End Enum
    ''' <summary>
    ''' 选择类型
    ''' </summary>
    ''' <remarks></remarks>
    Public CurrentSelectType As SelectType
    ''' <summary>
    ''' 更新选中区域
    ''' </summary>
    ''' <param name="orgPosition">原始插入点</param>
    ''' <remarks></remarks>
    Public Sub UpdateSelection(ByVal orgPosition As Point)
        Dim OldStartPos As Point = SelectStartRealPos
        Dim OldEndPos As Point = SelectEndRealPos
        If (SelectStartRealPos.X = 0 And SelectStartRealPos.Y = 0) Then
            '如果选中文本起点是(0,0)的情况
            SelectStartRealPos = MinPoint(orgPosition, InputPosition)
            SelectEndRealPos = MaxPoint(orgPosition, InputPosition)
        Else
            '式样：如果原来插入点在选中的头部，那么原来选中的尾部，成为这次头部
            '也就是说，原来插入点另外的一侧，成为这次的头部
            If ComparePoint(orgPosition, SelectStartRealPos) = CompareResult.Equal Then
                SelectStartRealPos = SelectEndRealPos
            End If
            '这两句不能调换次序！
            SelectEndRealPos = MaxPoint(InputPosition, SelectStartRealPos)
            SelectStartRealPos = MinPoint(InputPosition, SelectStartRealPos)
        End If
        ClearOldSelection(OldStartPos, OldEndPos)
        '如果是行代码块选中的话
        If ExRealLineManager.GetInfoLine(SelectEndRealPos.Y).Real_IsBlockHeader And ExRealLineManager.GetInfoLine(SelectEndRealPos.Y).Real_IsFolder Then
            Dim EndBlock As Integer = GetBlockFooterRealNo(SelectEndRealPos.Y)
            DisplayPosition = GetDisplayPosByInputPos(New Point(GetRealLineText(SelectEndRealPos.Y).Length + 1, SelectEndRealPos.Y))
            If SelectEndRealPos.Y = SelectStartRealPos.Y Then
                SelectStartRealPos = New Point(1, SelectStartRealPos.Y)
            End If
            SelectEndRealPos = New Point(GetRealLineText(EndBlock).Length + 1, EndBlock)
            InputPosition = SelectEndRealPos
        End If
        SetNewSelection()
    End Sub
    ''' <summary>
    ''' 更新选中区域(强制设定)
    ''' </summary>
    ''' <param name="selRealStart"></param>
    ''' <param name="selRealEnd"></param>
    ''' <remarks></remarks>
    Public Sub UpdateSelection(ByVal selRealStart As Point, ByVal selRealEnd As Point)
        Dim OldStartPos As Point = SelectStartRealPos
        Dim OldEndPos As Point = SelectEndRealPos
        SelectStartRealPos = selRealStart
        SelectEndRealPos = selRealEnd
        ClearOldSelection(OldStartPos, OldEndPos)
        SetNewSelection()
    End Sub
    ''' <summary>
    ''' 重新设定选中部分
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub SetNewSelection()
        Select Case SelectEndRealPos.Y - SelectStartRealPos.Y
            Case 0
                '如果开始的行和结束的行一样的话，说明选中部分只有一行
                ExRealLineManager.SelectText(SelectStartRealPos.Y, SelectStartRealPos.X, SelectEndRealPos.X - SelectStartRealPos.X)
            Case 1
                '如果开始的行和结束的行相差一行的话，说明选中部分有两行
                ExRealLineManager.SelectToEnd(SelectStartRealPos.Y, SelectStartRealPos.X)
                ExRealLineManager.SelectToHeader(SelectEndRealPos.Y, SelectEndRealPos.X)
            Case Else
                '多行的情况
                ExRealLineManager.SelectToEnd(SelectStartRealPos.Y, SelectStartRealPos.X)
                For temp As Integer = SelectStartRealPos.Y + 1 To SelectEndRealPos.Y - 1
                    ExRealLineManager.SelectAll(temp)
                Next
                ExRealLineManager.SelectToHeader(SelectEndRealPos.Y, SelectEndRealPos.X)
        End Select
        CurrentSelectType = SelectType.Normal
    End Sub
    ''' <summary>
    ''' 清除旧的选择文本[这个方法不改变选中起始和终止位置]
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub ClearOldSelection(ByVal oldStartPos As Point, ByVal oldEndPos As Point)
        If oldStartPos.Y = 0 Then Exit Sub
        For temp As Integer = oldStartPos.Y To oldEndPos.Y
            ExRealLineManager.UnSelectAll(temp)
        Next
    End Sub
    ''' <summary>
    ''' 清除旧的选择文本
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub ClearSelection()
        If SelectStartRealPos.Y > 0 Then
            '当删除块的时候,可能出现SelectEndPos.Y已经不存在的可能性
            For temp As Integer = SelectStartRealPos.Y To Math.Min(SelectEndRealPos.Y, MaxRealLineNumber)
                ExRealLineManager.UnSelectAll(temp)
            Next
        End If
        SelectStartRealPos = New Point(0, 0)
        SelectEndRealPos = New Point(0, 0)
    End Sub
    ''' <summary>
    ''' 获得选中文本
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GetSelectionText() As String
        Dim strSelectiong As String = String.Empty
        Dim SelStart As Integer
        Dim SelEnd As Integer
        If SelectStartRealPos <> Nothing Then
            '确定选中行的第一行
            SelStart = ExRealLineManager.GetMemPosByRealPos(SelectStartRealPos).Y
            '确定选中行的最后一行
            SelEnd = ExRealLineManager.GetMemPosByRealPos(SelectEndRealPos).Y
            If ExWordWrapMode Then
                For SelCount As Integer = SelStart To SelEnd
                    If GetMemoryLine(SelCount).SelectStart > 0 Then
                        '箱型的时候，会出现选中开始为0的情况
                        strSelectiong &= Mid(GetMemoryLine(SelCount).Text, GetMemoryLine(SelCount).SelectStart, GetMemoryLine(SelCount).SelectLength)
                    End If
                    If GetMemoryLine(SelCount).Dis_IsLastLine And (SelCount <> SelEnd) Then
                        strSelectiong &= vbCrLf
                    End If
                Next
            Else
                For SelCount As Integer = SelStart To SelEnd
                    If GetMemoryLine(SelCount).SelectStart > 0 Then
                        '箱型的时候，会出现选中开始为0的情况
                        strSelectiong &= Mid(GetMemoryLine(SelCount).Text, GetMemoryLine(SelCount).SelectStart, GetMemoryLine(SelCount).SelectLength)
                    End If
                    If SelCount <> SelEnd Then strSelectiong &= vbCrLf
                Next
            End If
        End If
        Return strSelectiong
    End Function
#End Region
#Region "选择系(箱型)"
    ''' <summary>
    ''' 更新选中区域
    ''' </summary>
    ''' <param name="orgPosition">原始插入点</param>
    ''' <param name="Left">左边距</param>
    ''' <param name="Right">右边距</param>
    ''' <remarks></remarks>
    Public Sub UpdateBoxSelection(ByVal orgPosition As Point, ByVal Left As Integer, ByVal Right As Integer)
        Dim OldStartPos As Point = SelectStartRealPos
        Dim OldEndPos As Point = SelectEndRealPos
        If (SelectStartRealPos.X = 0 And SelectStartRealPos.Y = 0) Then
            '如果选中文本起点是(0,0)的情况
            SelectStartRealPos = MinPoint(orgPosition, InputPosition)
            SelectEndRealPos = MaxPoint(orgPosition, InputPosition)
        Else
            '式样：如果原来插入点在选中的头部，那么原来选中的尾部，成为这次头部
            '也就是说，原来插入点另外的一侧，成为这次的头部
            If ComparePoint(orgPosition, SelectStartRealPos) = CompareResult.Equal Then
                SelectStartRealPos = SelectEndRealPos
            End If
            '这两句不能调换次序！
            SelectEndRealPos = MaxPoint(InputPosition, SelectStartRealPos)
            SelectStartRealPos = MinPoint(InputPosition, SelectStartRealPos)
        End If
        ClearOldSelection(OldStartPos, OldEndPos)
        SetNewBoxSelection(Math.Min(Left, Right), Math.Max(Left, Right))
    End Sub
    ''' <summary>
    ''' 重新设定选中部分(箱型)
    ''' </summary>
    ''' <param name="Left">左边距</param>
    ''' <param name="Right">右边距</param>
    ''' <remarks></remarks>
    Sub SetNewBoxSelection(ByVal Left As Integer, ByVal Right As Integer)
        Dim LineStartPos As Integer
        Dim LineEndPos As Integer
        For tempCount As Integer = SelectStartRealPos.Y To SelectEndRealPos.Y
            '如果行没有被折叠的话,可见的话
            If Not (ExRealLineManager.GetInfoLine(tempCount).Real_IsFolder Or ExRealLineManager.GetInfoLine(tempCount).Real_IsHidden) Then
                With GetMemoryLine(tempCount)
                    LineStartPos = 0
                    LineEndPos = 0
                    If .Text <> String.Empty Then
                        Dim strText As String = .Text
                        Dim MidPos As Single
                        If MeasureTextWidth(strText) > Left Then
                            '寻找起始位置
                            For Xpos As Integer = 1 To strText.Length
                                If MeasureTextWidth(Mid(strText, 1, Xpos)) > Left Then
                                    MidPos = (MeasureTextWidth(Mid(strText, 1, Xpos)) + MeasureTextWidth(Mid(strText, 1, Xpos - 1))) / 2
                                    If Left < MidPos Then
                                        LineStartPos = Xpos
                                    Else
                                        LineStartPos = Xpos + 1
                                    End If
                                    Exit For
                                End If
                            Next
                            '寻找终止位置
                            For Xpos As Integer = LineStartPos To strText.Length
                                If MeasureTextWidth(Mid(strText, 1, Xpos)) > Right Then
                                    MidPos = (MeasureTextWidth(Mid(strText, 1, Xpos - 1)) + MeasureTextWidth(Mid(strText, 1, Xpos))) / 2
                                    If Right < MidPos Then
                                        LineEndPos = Xpos
                                    Else
                                        LineEndPos = Xpos + 1
                                    End If
                                    Exit For
                                End If
                            Next
                            If LineStartPos <> 0 And LineEndPos = 0 Then
                                LineEndPos = .Text.Length
                                ExRealLineManager.SelectText(tempCount, LineStartPos, LineEndPos - LineStartPos + 1)
                                If tempCount = SelectEndRealPos.Y Then InputPosition = New Point(LineEndPos + 1, tempCount)
                            Else
                                If LineEndPos > LineStartPos Then
                                    ExRealLineManager.SelectText(tempCount, LineStartPos, LineEndPos - LineStartPos)
                                    If tempCount = SelectEndRealPos.Y Then InputPosition = New Point(LineEndPos, tempCount)
                                Else
                                    If tempCount = SelectEndRealPos.Y Then InputPosition = New Point(1, tempCount)
                                End If
                            End If
                        End If
                    End If
                End With
            End If
        Next
        CurrentSelectType = SelectType.Box
    End Sub
#End Region
#Region "列模式"
    ''' <summary>
    ''' 用于列模式的数据[Key是插入点的行号，Value是插入点的列号]
    ''' </summary>
    ''' <remarks></remarks>
    Public ColumnModeList As New Dictionary(Of Integer, Integer)
    Public FirstColumnLine As Integer
    Public LastColumnLine As Integer
    ''' <summary>
    ''' 设置类模式
    ''' </summary>
    ''' <param name="FirstLine"></param>
    ''' <param name="LastLine"></param>
    ''' <param name="Left"></param>
    ''' <remarks></remarks>
    Sub SetColumn(ByVal FirstLine As Integer, ByVal LastLine As Integer, ByVal Left As Integer)
        ColumnModeList.Clear()
        FirstColumnLine = FirstLine
        LastColumnLine = LastLine
        For i As Integer = FirstLine To LastLine
            Dim StartColumn As Integer = 0
            If GetMemoryLine(i).Text <> String.Empty Then
                For t = 1 To GetMemoryLine(i).Text.Length
                    If CInt(MeasureTextWidth(Mid(GetMemoryLine(i).Text, 1, t))) >= Left Then
                        StartColumn = t
                        Exit For
                    End If
                Next
            End If
            If StartColumn = 0 Then StartColumn = GetMemoryLine(i).Text.Length
            StartColumn = StartColumn + 1
            ColumnModeList.Add(i, StartColumn)
        Next
    End Sub
#End Region
#Region "折行显示"
    Public WordWrapWidth As Integer
    ''' <summary>
    ''' 恢复折行拆分
    ''' </summary>
    ''' <remarks></remarks>
    Sub UnDoWrapWord()
        'TODO:需要重新写逻辑
        Dim UnWrapList As New List(Of Line)
        Dim strLineText As String = String.Empty
        '需要重新写DisplayManager
        ExDisplayManager.Clear()
        For i As Integer = 1 To MemoryLines.Count
            strLineText = strLineText & MemoryLines(i - 1).Text
            If MemoryLines(i - 1).Dis_IsLastLine Then
                '如果这个行是末行的时候
                Dim NewLine As New Line
                '继承需要的一些属性
                NewLine = ExRealLineManager.GetInfoLine(MemoryLines(i - 1).Dis_RealLineNumber)
                NewLine.Text = strLineText
                NewLine.Dis_IsFirstLine = True
                NewLine.Dis_IsLastLine = True
                NewLine.Dis_CurrentLineNo = 1
                NewLine.Dis_TotalCount = 1
                NewLine.Real_MemoryStartLineNo = UnWrapList.Count + 1
                NewLine.Real_MemoryEndLineNo = UnWrapList.Count + 1
                NewLine.Dis_RealLineNumber = UnWrapList.Count + 1
                UnWrapList.Add(NewLine)
                If ExRealLineManager.GetInfoLine(MemoryLines(i - 1).Dis_RealLineNumber).Real_IsHidden = False Then
                    ExDisplayManager.Add(UnWrapList.Count)
                End If
                strLineText = String.Empty
            End If
        Next
        Dim MaxLine As Integer = ExRealLineManager.Count
        ExRealLineManager.Clear()
        For i As Integer = 1 To MaxLine
            ExRealLineManager.Add(i)
        Next
        MemoryLines = UnWrapList
        UnWrapList = Nothing
        '重新设置标志
        ResetFlags()
        '高亮显示
        SetHeightLightWord(mHeightLightWord)
        InputPosition = New Point(1, 1)
        DisplayPosition = New Point(1, 1)
        If SelectStartRealPos.X <> 0 Then
            UpdateSelection(SelectStartRealPos, SelectEndRealPos)
        End If
    End Sub
    ''' <summary>
    ''' 进行折行拆分
    ''' </summary>
    ''' <param name="Width">宽度</param>
    ''' <remarks></remarks>
    Sub DoWrapWord(ByVal Width As Integer)
        WordWrapWidth = Width
        DoWrapWord()
    End Sub
    ''' <summary>
    ''' 进行折行拆分
    ''' </summary>
    ''' <remarks></remarks>
    Sub DoWrapWord()
        ExDisplayManager.Clear()
        '折行分析后的行列表
        Dim StrWrapWord As New List(Of Line)
        Dim MainLine As Line
        For i As Integer = 0 To MaxRealLineNumber - 1
            '折行前，真实行号和内存行号一致（相差1）
            MainLine = MemoryLines(i)
            Dim SubLines As List(Of Line) = GetSubLines(MainLine)
            '这里的逻辑变更的时候，不要忘记变更下面的逻辑！
            If SubLines.Count = 1 Then
                Dim SingleLine As New Line
                '继承需要的一些属性
                SingleLine = MainLine
                SingleLine.Text = SubLines(0).Text
                SingleLine.Real_MemoryStartLineNo = StrWrapWord.Count + 1
                SingleLine.Real_MemoryEndLineNo = StrWrapWord.Count + 1
                SingleLine.Dis_IsFirstLine = True
                SingleLine.Dis_IsLastLine = True
                SingleLine.Dis_RealLineNumber = i + 1
                SingleLine.Dis_CurrentLineNo = 1
                SingleLine.Dis_TotalCount = 1
                StrWrapWord.Add(SingleLine)
                If ExRealLineManager.GetInfoLine(i + 1).Real_IsHidden = False Then
                    ExDisplayManager.Add(StrWrapWord.Count)
                End If
                '调整真实队列里首个内存行
                ExRealLineManager.Replace(i + 1, StrWrapWord.Count)
            Else
                Dim StartLine As New Line
                '继承需要的一些属性
                StartLine = MainLine
                StartLine.Text = SubLines(0).Text
                StartLine.Dis_IsFirstLine = True
                StartLine.Dis_IsLastLine = False
                StartLine.Dis_RealLineNumber = i + 1
                StartLine.Dis_CurrentLineNo = 1
                StartLine.Dis_TotalCount = SubLines.Count
                StartLine.Real_MemoryStartLineNo = StrWrapWord.Count + 1
                StartLine.Real_MemoryEndLineNo = StrWrapWord.Count + SubLines.Count
                StrWrapWord.Add(StartLine)
                If ExRealLineManager.GetInfoLine(i + 1).Real_IsHidden = False Then
                    ExDisplayManager.Add(StrWrapWord.Count)
                End If
                If SubLines.Count > 2 Then
                    For T As Integer = 1 To SubLines.Count - 2
                        Dim MidLine As Line
                        MidLine = SubLines(T)
                        MidLine.Dis_IsFirstLine = False
                        MidLine.Dis_IsLastLine = False
                        MidLine.Dis_RealLineNumber = i + 1
                        MidLine.Dis_CurrentLineNo = T + 1
                        MidLine.Dis_TotalCount = SubLines.Count
                        StrWrapWord.Add(MidLine)
                        If ExRealLineManager.GetInfoLine(i + 1).Real_IsHidden = False Then
                            ExDisplayManager.Add(StrWrapWord.Count)
                        End If
                    Next
                End If
                Dim EndLine As Line
                EndLine = SubLines(SubLines.Count - 1)
                EndLine.Dis_IsFirstLine = False
                EndLine.Dis_IsLastLine = True
                EndLine.Dis_RealLineNumber = i + 1
                EndLine.Dis_CurrentLineNo = SubLines.Count
                EndLine.Dis_TotalCount = SubLines.Count
                StrWrapWord.Add(EndLine)
                If ExRealLineManager.GetInfoLine(i + 1).Real_IsHidden = False Then
                    ExDisplayManager.Add(StrWrapWord.Count)
                End If
                '调整真实队列里首个内存行
                ExRealLineManager.Replace(i + 1, StrWrapWord.Count - SubLines.Count + 1)
            End If
        Next
        MemoryLines = StrWrapWord
        StrWrapWord = Nothing
        '重新设置标志
        ResetFlags()
        '高亮显示
        SetHeightLightWord(mHeightLightWord)
        InputPosition = New Point(1, 1)
        DisplayPosition = New Point(1, 1)
        If SelectStartRealPos.X <> 0 Then
            UpdateSelection(SelectStartRealPos, SelectEndRealPos)
        End If
    End Sub
    ''' <summary>
    ''' 将一个整行拆成若干子行
    ''' </summary>
    ''' <param name="MainLine"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GetSubLines(ByVal MainLine As Line) As List(Of Line)
        Dim SubLines As New List(Of Line)
        If MainLine.Width <= WordWrapWidth Then
            Dim SingleLine As Line
            SingleLine = MainLine
            SubLines.Add(SingleLine)
        Else
            'TODO: 折行策略
            Dim RealRemainText As String = MainLine.Text
            '新行的行首位置
            Dim LineHeader As Integer = 1
            '每次测试宽度使用的文本
            Dim TestWord As String
            '每次测试的宽度
            Dim TestLength As Integer
            '遍历所有单词开始位置
            Dim checkPoint As Integer = 0
            '最后位置
            Dim EndPoint As Integer = 1
            Do Until checkPoint = MainLine.WordList.Count + 1

                If checkPoint <> MainLine.WordList.Count Then
                    EndPoint = MainLine.WordList(checkPoint).StartPos
                Else
                    EndPoint = RealRemainText.Length - 1
                End If

                '如果开始位置和单词开始位置一样的话，跳过这个单词
                If LineHeader <> EndPoint Then
                    '测试文本长度为行开始位置到单词的前一个字符位置
                    TestLength = EndPoint - LineHeader
                    TestWord = Mid(RealRemainText, LineHeader, TestLength)
                    If MeasureTextWidth(TestWord) > WordWrapWidth Then
                        '如果从开始测试点到当前词的宽度大于屏幕，进行分行处理
                        '逐步减少文本长度，直到能够放入屏幕
                        For NewTestLength As Integer = TestLength - 1 To 1 Step -1
                            If MeasureTextWidth(Mid(RealRemainText, LineHeader, NewTestLength)) <= WordWrapWidth _
                                And (DelimitMark.Contains(Mid(RealRemainText, LineHeader + NewTestLength - 1, 1)) Or _
                                     Mid(RealRemainText, LineHeader + NewTestLength - 1, 1) = Space(1)) Then
                                '确定了最大可用长度了,则新增行
                                SubLines.Add(New Line(Mid(RealRemainText, LineHeader, NewTestLength)))
                                LineHeader = LineHeader + NewTestLength
                                checkPoint -= 1
                                Exit For
                            End If
                        Next
                    End If
                End If
                checkPoint += 1
            Loop
            '如果开始位置不比整个字符大，最后剩下的为一行。
            If LineHeader <= RealRemainText.Length Then
                '考虑到超长字符的问题
                If MeasureTextWidth(Mid(RealRemainText, LineHeader)) <= WordWrapWidth Then
                    SubLines.Add(New Line(Mid(RealRemainText, LineHeader)))
                Else
                    'TODO: 按照位置切割
                    Do Until MeasureTextWidth(Mid(RealRemainText, LineHeader)) <= WordWrapWidth
                        For i As Integer = 1 To Mid(RealRemainText, LineHeader).Length
                            If MeasureTextWidth(Mid(RealRemainText, LineHeader, i)) > WordWrapWidth Then
                                SubLines.Add(New Line(Mid(RealRemainText, LineHeader, i - 1)))
                                LineHeader += i - 1
                                Exit For
                            End If
                        Next
                    Loop
                    SubLines.Add(New Line(Mid(RealRemainText, LineHeader)))
                End If
            End If
        End If
        Return SubLines
        ResetFlags()
    End Function
    ''' <summary>
    ''' 重新对一个真实行进行重新排版
    ''' </summary>
    ''' <param name="RealLineNumber"></param>
    ''' <remarks></remarks>
    Sub ReWrapLine(ByVal RealLineNumber As Integer)
        '获得文本
        Dim strText As String = String.Empty
        Dim FirstLine As New Line
        FirstLine = ExRealLineManager.GetInfoLine(RealLineNumber)
        For i As Integer = FirstLine.Real_MemoryStartLineNo To FirstLine.Real_MemoryEndLineNo
            strText &= GetMemoryLine(i).Text
        Next
        For i As Integer = FirstLine.Real_MemoryStartLineNo To FirstLine.Real_MemoryEndLineNo
            '删除内存行
            MemoryLines.RemoveAt(FirstLine.Real_MemoryStartLineNo - 1)
        Next
        '重新排版
        Dim NewLines As List(Of Line) = GetSubLines(New Line(strText))
        '添加内存行
        If NewLines.Count = 1 Then
            Dim SingleLine As Line
            SingleLine = NewLines(0)
            SingleLine.Real_MemoryStartLineNo = FirstLine.Real_MemoryStartLineNo
            SingleLine.Real_MemoryEndLineNo = FirstLine.Real_MemoryStartLineNo
            SingleLine.Dis_IsFirstLine = True
            SingleLine.Dis_IsLastLine = True
            SingleLine.Dis_RealLineNumber = RealLineNumber
            SingleLine.Dis_CurrentLineNo = 1
            SingleLine.Dis_TotalCount = 1
            SingleLine.Real_IsHidden = FirstLine.Real_IsHidden
        Else
            Dim StartLine As Line
            StartLine = NewLines(0)
            StartLine.Dis_IsFirstLine = True
            StartLine.Dis_IsLastLine = False
            StartLine.Dis_RealLineNumber = RealLineNumber
            StartLine.Dis_CurrentLineNo = 1
            StartLine.Dis_TotalCount = NewLines.Count
            StartLine.Real_IsHidden = FirstLine.Real_IsHidden
            StartLine.Real_MemoryStartLineNo = FirstLine.Real_MemoryStartLineNo
            StartLine.Real_MemoryEndLineNo = FirstLine.Real_MemoryStartLineNo + NewLines.Count - 1
            If NewLines.Count > 2 Then
                For T As Integer = 1 To NewLines.Count - 2
                    Dim MidLine As Line
                    MidLine = NewLines(T)
                    MidLine.Dis_IsFirstLine = False
                    MidLine.Dis_IsLastLine = False
                    MidLine.Dis_RealLineNumber = RealLineNumber
                    MidLine.Dis_CurrentLineNo = T + 1
                    MidLine.Dis_TotalCount = NewLines.Count
                Next
            End If
            Dim EndLine As Line
            EndLine = NewLines(NewLines.Count - 1)
            EndLine.Dis_IsFirstLine = False
            EndLine.Dis_IsLastLine = True
            EndLine.Dis_RealLineNumber = RealLineNumber
            EndLine.Dis_CurrentLineNo = NewLines.Count
            EndLine.Dis_TotalCount = NewLines.Count
        End If
        For i As Integer = 0 To NewLines.Count - 1
            MemoryLines.Insert(FirstLine.Real_MemoryStartLineNo - 1 + i, NewLines(i))
        Next
        If (FirstLine.Real_MemoryEndLineNo - FirstLine.Real_MemoryStartLineNo + 1) <> NewLines.Count Then
            '如果重新排版造成行数变化的时候
            Dim DisplayStart As Integer = ExDisplayManager.GetDisplayNoByMemoryNo(FirstLine.Real_MemoryStartLineNo)
            '删除表示行[RemoveLines里面自动修正了内存行号]
            ExDisplayManager.RemoveLinesByDelLine(DisplayStart, FirstLine.Real_MemoryEndLineNo - FirstLine.Real_MemoryStartLineNo + 1, DisplayLineManager.JustfiyMode.ALL)
            '添加表示行[InsertLines里面自动修正了内存行号]
            ExDisplayManager.InsertLinesByAddLine(DisplayStart, FirstLine.Real_MemoryStartLineNo, NewLines.Count, DisplayLineManager.JustfiyMode.ALL)
            Dim Delta As Integer = NewLines.Count - (FirstLine.Real_MemoryEndLineNo - FirstLine.Real_MemoryStartLineNo + 1)
            For i As Integer = RealLineNumber + 1 To MaxRealLineNumber
                ExRealLineManager.ReplaceByDelta(i, Delta)
                ExRealLineManager.GetInfoLine(i).Real_MemoryStartLineNo += Delta
                ExRealLineManager.GetInfoLine(i).Real_MemoryEndLineNo += Delta
            Next
        End If
        '高亮显示
        With ExRealLineManager.GetInfoLine(RealLineNumber)
            For i As Integer = .Real_MemoryStartLineNo To .Real_MemoryEndLineNo
                GetMemoryLine(i).ResetHeightLightWord(mHeightLightWord)
            Next
        End With
    End Sub
#End Region
#Region "代码折叠"
    ''' <summary>
    ''' 折叠代码
    ''' </summary>
    ''' <param name="DisplayLineNo">折叠开始行</param>
    ''' <remarks>折叠开始行是可见的</remarks>
    Sub Folder(ByVal DisplayLineNo As Integer)
        Dim memoryLine As Line = GetMemoryLineByDisplayLineNumber(DisplayLineNo)
        '将行设为不可见,这个真实行可见，
        Dim StartRealLineNo As Integer = memoryLine.Dis_RealLineNumber
        Dim EndRealLineNo As Integer
        EndRealLineNo = GetBlockFooterRealNo(StartRealLineNo)
        If EndRealLineNo <> 0 Then
            Dim DisplayStartNo As Integer
            Dim DisplayEndNo As Integer
            DisplayStartNo = ExDisplayManager.GetDisplayNoByMemoryNo(ExRealLineManager.GetInfoLine(StartRealLineNo + 1).Real_MemoryStartLineNo)
            DisplayEndNo = ExDisplayManager.GetDisplayNoByMemoryNo(ExRealLineManager.GetInfoLine(EndRealLineNo).Real_MemoryEndLineNo)
            If DisplayEndNo = 0 Then
                '没有明显的结束标志。依靠下一个段落作为前一个段落的结尾。
                '但是，内部的最后一个子块又处于折叠的状态
                '从EndRealLineNo开始，向上寻找一个可见的行。
                For i As Integer = EndRealLineNo To 1 Step -1
                    DisplayEndNo = ExDisplayManager.GetDisplayNoByMemoryNo(ExRealLineManager.GetInfoLine(i).Real_MemoryEndLineNo)
                    If DisplayEndNo <> 0 Then Exit For
                Next
            End If
            ExDisplayManager.RemoveLinesByDelLine(DisplayStartNo, DisplayEndNo - DisplayStartNo + 1, DisplayLineManager.JustfiyMode.ProcessFirstLine)
            For i As Integer = StartRealLineNo + 1 To EndRealLineNo
                ExRealLineManager.GetInfoLine(i).Real_IsHidden = True
            Next
            DisplayStartNo = ExDisplayManager.GetDisplayNoByMemoryNo(ExRealLineManager.GetInfoLine(StartRealLineNo).Real_MemoryStartLineNo)
            If Not (DisplayPosition.Y < DisplayStartNo) Then
                If Not (DisplayPosition.Y > DisplayEndNo) Then
                    '如果光标在代码段里面，把光标换到代码段的开始位置
                    DisplayPosition = New Point(1, DisplayStartNo)
                Else
                    DisplayPosition = New Point(DisplayPosition.X, DisplayPosition.Y - DisplayEndNo + DisplayStartNo)
                End If
            End If
            '是否展开设定为真
            memoryLine.Real_IsFolder = True
        End If
        '清除选中区域
        If HasSelection Then ClearSelection()
    End Sub
    ''' <summary>
    ''' 展开代码
    ''' </summary>
    ''' <param name="DisplayLineNo"></param>
    ''' <remarks></remarks>
    Sub Expend(ByVal DisplayLineNo As Integer)
        Dim memoryLine As Line = GetMemoryLineByDisplayLineNumber(DisplayLineNo)
        '将行设为不可见,这个真实行可见，
        Dim StartRealLineNo As Integer = memoryLine.Dis_RealLineNumber
        Dim EndRealLineNo As Integer
        EndRealLineNo = GetBlockFooterRealNo(StartRealLineNo)
        If EndRealLineNo <> 0 Then
            Dim DisplayStartNo As Integer
            Dim DisplayStartNoOrg As Integer
            DisplayStartNo = ExDisplayManager.GetDisplayNoByMemoryNo(ExRealLineManager.GetInfoLine(StartRealLineNo).Real_MemoryEndLineNo) + 1
            DisplayStartNoOrg = DisplayStartNo
            '需要展开的部分才能展开            
            '原本处于折叠状态的代码维持原来的状态
            Dim LoopCount As Integer
            LoopCount = StartRealLineNo + 1
            Do While LoopCount <= EndRealLineNo
                With ExRealLineManager.GetInfoLine(LoopCount)
                    For t As Integer = .Real_MemoryStartLineNo To .Real_MemoryEndLineNo
                        ExDisplayManager.InsertLinesByAddLine(DisplayStartNo, t, 1, DisplayLineManager.JustfiyMode.ProcessFirstLine)
                        DisplayStartNo += 1
                    Next
                    ExRealLineManager.GetInfoLine(LoopCount).Real_IsHidden = False
                    If .Real_IsBlockHeader And .Real_IsFolder Then
                        '如果这个行是代码块的头部，而且这个块是隐藏的，则考虑能否跳过这个块的表示
                        Dim EndBlock As Integer = GetBlockFooterRealNo(LoopCount)
                        '如果这个块可以闭合的话，跳过这个块
                        If EndBlock <> 0 Then
                            LoopCount = EndBlock + 1
                        Else
                            LoopCount += 1
                        End If
                    Else
                        LoopCount += 1
                    End If
                End With
            Loop
            If DisplayPosition.Y > ExDisplayManager.GetDisplayNoByMemoryNo(ExRealLineManager.GetInfoLine(StartRealLineNo).Real_MemoryStartLineNo) Then
                DisplayPosition = New Point(DisplayPosition.X, DisplayPosition.Y + DisplayStartNo - DisplayStartNoOrg)
            End If
            '是否展开设定为假
            memoryLine.Real_IsFolder = False
        End If
    End Sub
    ''' <summary>
    ''' 代码折叠
    ''' </summary>
    ''' <remarks></remarks>
    Sub SetAllSyntax()
        If MaxRealLineNumber <= 1 Then Exit Sub
        For CountLoop As Integer = 1 To MaxRealLineNumber
            '对每一行进行段落首尾的标记
            SetSyntax(CountLoop)
        Next
        '重新设置能不能被折叠的行属性
        ResetFlags()
    End Sub
    ''' <summary>
    ''' 设置折叠代码段首尾标志
    ''' </summary>
    ''' <param name="RealLineNumber"></param>
    ''' <remarks></remarks>
    Sub SetSyntax(ByVal RealLineNumber As Integer)
        With ExRealLineManager.GetInfoLine(RealLineNumber)
            '初始化
            .Real_IsBlockHeader = False
            .Real_IsBlockFooter = False
            .Real_IsBlockNeedFooter = False
            .Real_BlockKeyWord.Clear()
            .Real_CanBeFolder = False
            .Real_IsFolder = False
            If Not .Real_IsCommentLine Then
                If ExSyntaxKeyList.Count = 0 Then Exit Sub
                '普通规则的处理
                For Each mSytaxKey In ExSyntaxKeyList
                    '如果存在关键字的话
                    If syntaxDetail(mSytaxKey, ExRealLineManager.GetInfoLine(RealLineNumber)) = False Then Exit For
                Next
            End If
        End With
    End Sub
    ''' <summary>
    ''' 判断匹配段落首尾的方法
    ''' </summary>
    ''' <param name="mSyntaxKey"></param>
    ''' <param name="mLine"></param>
    ''' <returns>是否需要判断余下的规则</returns>
    ''' <remarks></remarks>
    Function syntaxDetail(ByVal mSyntaxKey As SyntaxKey, ByVal mLine As Line) As Boolean
        Dim strText As String = UCase(GetRealLineText(mLine.Dis_RealLineNumber))
        If RegularExpressions.Regex.IsMatch(strText, mSyntaxKey.StartRule, RegularExpressions.RegexOptions.IgnoreCase) Then
            '对于StartRule进行检查
            mLine.Real_IsBlockHeader = True
            mLine.Real_BlockLV = mSyntaxKey.LV
            If mSyntaxKey.EndRule = String.Empty Then
                mLine.Real_IsBlockNeedFooter = False
            Else
                mLine.Real_IsBlockNeedFooter = True
            End If
            mLine.Real_BlockKeyWord.Add(mSyntaxKey.KeyWord)
            Return False
        End If
        If mSyntaxKey.EndRule = String.Empty Then Return True
        If RegularExpressions.Regex.IsMatch(strText, mSyntaxKey.EndRule, RegularExpressions.RegexOptions.IgnoreCase) Then
            '对于EndRule进行检查
            mLine.Real_IsBlockFooter = True
            mLine.Real_BlockKeyWord.Add(mSyntaxKey.KeyWord)
        End If
        Return True
    End Function
    ''' <summary>
    ''' 根据块首获得匹配的结尾真实行位置
    ''' </summary>
    ''' <param name="StartRealLineNo"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GetBlockFooterRealNo(ByVal StartRealLineNo As Integer) As Integer
        Dim EndRealLineNo As Integer = 0
        If ExRealLineManager.GetInfoLine(StartRealLineNo).Real_IsBlockNeedFooter Then
            Dim StrKey As String = ExRealLineManager.GetInfoLine(StartRealLineNo).Real_BlockKeyWord(0)
            '需要明示的结尾
            For i As Integer = StartRealLineNo + 1 To MaxRealLineNumber
                '如果遇上结束标志，检查这个结束标志的关键字
                If ExRealLineManager.GetInfoLine(i).Real_IsBlockFooter Then
                    Dim IsMatch As Boolean = False
                    For Each strT As String In ExRealLineManager.GetInfoLine(i).Real_BlockKeyWord
                        If strT = StrKey Then
                            IsMatch = True
                            Exit For
                        End If
                    Next
                    If IsMatch Then
                        EndRealLineNo = i
                        Exit For
                    End If
                End If
                '如果遇上同级或上级开始标志，返回0
                If ExRealLineManager.GetInfoLine(i).Real_IsBlockHeader And _
                   ExRealLineManager.GetInfoLine(i).Real_BlockLV <= _
                   ExRealLineManager.GetInfoLine(StartRealLineNo).Real_BlockLV Then
                    Exit For
                End If
            Next
        Else
            '不需要明示的结尾。遇到EOF，或者同级，或者上级的东西，前一行则认为是尾部
            For i As Integer = StartRealLineNo + 1 To MaxRealLineNumber
                '如果遇上结束标志，检查这个结束标志的关键字
                If ExRealLineManager.GetInfoLine(i).Real_IsBlockHeader Then
                    If ExRealLineManager.GetInfoLine(i).Real_BlockLV <= ExRealLineManager.GetInfoLine(StartRealLineNo).Real_BlockLV Then
                        EndRealLineNo = i - 1
                        Exit For
                    End If
                End If
            Next
            If EndRealLineNo = 0 Then
                EndRealLineNo = MaxRealLineNumber
            End If
            '补上一个结束符号
            ExRealLineManager.GetInfoLine(EndRealLineNo).Real_IsBlockFooter = True
            If EndRealLineNo > 1 Then
                '清除因为插入行的关系，使当前行和上面一行同时又结束标记的可能性
                ExRealLineManager.GetInfoLine(EndRealLineNo - 1).Real_IsBlockFooter = False
            End If
        End If
        Return EndRealLineNo
    End Function
    ''' <summary>
    ''' 获取代码段内容用于显示
    ''' </summary>
    ''' <param name="StartRealLineNumber"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GetBlockText(ByVal StartRealLineNumber As Integer) As String
        Dim strRtn As String = String.Empty
        Dim EndRealLineNumber As Integer = GetBlockFooterRealNo(StartRealLineNumber)
        If EndRealLineNumber <> 0 Then
            Dim ShowLine As Integer = 0
            For i As Integer = StartRealLineNumber To EndRealLineNumber
                If ShowLine = 10 Then
                    strRtn &= "......"
                    Exit For
                End If
                strRtn &= GetRealLineText(i) & vbCrLf
                ShowLine += 1
            Next
        End If
        Return strRtn
    End Function
    ''' <summary>
    ''' 收缩所有代码
    ''' </summary>
    ''' <remarks></remarks>
    Sub CollapseALL()
        ExDisplayManager.Clear()
        For i As Integer = 1 To MaxRealLineNumber
            With ExRealLineManager.GetInfoLine(i)
                If .Real_IsBlockHeader Then
                    If GetBlockFooterRealNo(i) <> 0 Then .Real_IsFolder = True
                End If
                .Real_IsHidden = True
            End With
        Next
        Dim Count As Integer = 1
        Do While Count <= MaxRealLineNumber
            With ExRealLineManager.GetInfoLine(Count)
                If .Real_IsBlockHeader Then
                    '折行显示的时候，也只需要表示第一行
                    ExDisplayManager.Add(.Real_MemoryStartLineNo)
                    .Real_IsHidden = False
                    If GetBlockFooterRealNo(Count) = 0 Then
                        Count += 1
                    Else
                        Count = GetBlockFooterRealNo(Count) + 1
                    End If
                Else
                    '折行显示的时候，也只需要表示第一行
                    ExDisplayManager.Add(.Real_MemoryStartLineNo)
                    .Real_IsHidden = False
                    Count += 1
                End If
            End With
        Loop
        DisplayPosition = New Point(1, 1)
    End Sub
    ''' <summary>
    ''' 展开所有代码
    ''' </summary>
    ''' <remarks></remarks>
    Sub ExpandAll()
        ExDisplayManager.Clear()
        For LoopCount As Integer = 1 To MaxRealLineNumber
            With ExRealLineManager.GetInfoLine(LoopCount)
                .Real_IsFolder = False
                .Real_IsHidden = False
                '折行显示的时候，需要展开所有行
                For DispNo As Integer = .Real_MemoryStartLineNo To .Real_MemoryEndLineNo
                    ExDisplayManager.Add(DispNo)
                Next
            End With
        Next
        DisplayPosition = New Point(1, 1)
    End Sub
#End Region
#Region "书签"
    '6个成员的数组，存放书签行数
    Friend lstBookMark As New List(Of Integer)
    '下一个，下一个书签用
    Friend BookMarkPosition As Byte = 0
    ''' <summary>
    ''' 清除所有书签
    ''' </summary>
    ''' <remarks></remarks>
    Sub ClearBookMarks()
        lstBookMark.Clear()
    End Sub
    ''' <summary>
    ''' 增加书签
    ''' </summary>
    ''' <param name="RealLineNo">真实行号</param>
    ''' <remarks></remarks>
    Sub AddBookMark(ByVal RealLineNo As Integer)
        If Not lstBookMark.Contains(RealLineNo) Then lstBookMark.Add(RealLineNo)
        lstBookMark.Sort()
    End Sub
    ''' <summary>
    '''删除书签
    ''' </summary>
    ''' <param name="RealLineNo">真实行号</param>
    ''' <remarks></remarks>
    Sub DeleteBookMark(ByVal RealLineNo As Byte)
        If lstBookMark.Contains(RealLineNo) Then lstBookMark.Remove(RealLineNo)
        lstBookMark.Sort()
        BookMarkPosition = 0
    End Sub
    ''' <summary>
    ''' 上一个书签
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub PreviousBookMark()
        If BookMarkPosition > 0 Then
            BookMarkPosition -= 1
            If BookMarkPosition = 0 Then
                BookMarkPosition = lstBookMark.Count
            End If
            BookMarkPosition = Math.Min(BookMarkPosition, lstBookMark.Count)
        Else
            BookMarkPosition = lstBookMark.Count
        End If
    End Sub
    ''' <summary>
    ''' 下一个书签
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub NextBookMark()
        If BookMarkPosition <= 254 Then BookMarkPosition += 1
        If BookMarkPosition > lstBookMark.Count Then BookMarkPosition = 1
    End Sub
#End Region
End Class


